// MyDatabase.cpp: implementation of the CMyDatabase class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TDPsola.h"
#include "MyDatabase.h"
#include "MyConstants.h"
#include "Psola.h"
#include "LXH_Feature_MFCC.h"
//#include "afxtempl.h"
#include "iostream.h"
#include <fstream.h>
#include <iomanip.h>
#include <stdlib.h>


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
int			CMyDatabase::m_nErrorCode = DB_NOERROR;
CString		CMyDatabase::m_csError;
ofstream txtFile; //thaodv 250211

CMyDatabase::CMyDatabase(){
	this->m_bOpenedDB = FALSE;
	this->m_cHeader = new char [DB_HEADERSIZE]; 
	// DB_HEADERSIZE = Size of the Header of Database file, for 35000 acoustic Units; thaodv 180111	
	this->m_stSupInfo = new DIPSUPINFOS [2]; // typedef struct
	//m_stSupInfo: luu tru CSDL
	//this->PreUnit.wIndex = -1; // Bo xung ngay 10 thang 02: luu giu ket qua am duoc chon
	txtFile.open("txt_MyDatabase.txt"); //thaodv 250211
	txtFile.close();//thaodv 250211

	
}

CMyDatabase::~CMyDatabase(){
	delete[] this->m_cHeader;
	delete[] this->m_stSupInfo;
}

BOOL CMyDatabase::CreateDatabase(LPCTSTR lpszFileName){
	CFile fFile;
	if(!fFile.Open(lpszFileName,CFile::modeWrite | CFile::modeCreate)){
		m_nErrorCode = DB_CANNOTOPENDBFILE;
		m_csError.Format("Can not open database file : %s",lpszFileName);
		return FALSE;
	}
	char *cHeader = new char [DB_HEADERSIZE];
	memset(cHeader,0,DB_HEADERSIZE);
	fFile.Write(cHeader,DB_HEADERSIZE);
	delete[] cHeader;
	fFile.Close();
	return TRUE;
}

BOOL CMyDatabase::Open(LPCTSTR lpszFileName){
	if(!m_fAUnits.Open(lpszFileName,CFile::modeReadWrite)){
		if(!CreateDatabase(lpszFileName))
			return FALSE;
		m_fAUnits.Open(lpszFileName,CFile::modeReadWrite);
	}
	m_csFileName.Format("%s",lpszFileName);
	this->m_bOpenedDB = TRUE;

	m_fAUnits.Read(m_cHeader,DB_HEADERSIZE);
	delete[] this->m_stSupInfo;
	this->m_stSupInfo = new DIPSUPINFOS [*(WORD*)(m_cHeader)];
	this->ReadSupInfo();

	return TRUE;
}

void CMyDatabase::Close(){
	if(this->m_bOpenedDB){
		this->m_bOpenedDB = FALSE;
		m_fAUnits.Close();
	}
}


BOOL CMyDatabase::Reload(){
	if(!this->m_bOpenedDB) 
	{
		this->m_nErrorCode = DB_CANNOTRELOAD;
		return FALSE;
	}
	m_fAUnits.SeekToBegin();
	m_fAUnits.Read(m_cHeader,DB_HEADERSIZE);
	delete[] this->m_stSupInfo;
	this->m_stSupInfo = new DIPSUPINFOS [*(WORD*)(m_cHeader)];
	this->ReadSupInfo();
	return TRUE;
}


int CMyDatabase::FindAll(LPCTSTR lpszAUnitName)
{
	if(!this->m_bOpenedDB){
		m_nErrorCode = DB_DBNOTOPENED;
		return -1;
	}

	if(!lpszAUnitName){ 
		m_nErrorCode = DB_NULLPOINTER;
		return -1;
	}

	ASSERT(strlen(lpszAUnitName) < 5);

	char *lpszDBAUnitName = new char [5];
	lpszDBAUnitName[4] = '\0';
	BOOL	bFound = FALSE;
	int i;
	for(i = 0; i < *(WORD *)(m_cHeader);i++)
	{
		*(DWORD *)(lpszDBAUnitName) = *(DWORD *)(m_cHeader + i * 8 + 2);
		if(strcmp(lpszAUnitName,lpszDBAUnitName)==0){
			bFound = TRUE;
			break;
		}
	}
	delete[] lpszDBAUnitName;
	if(!bFound){
		m_nErrorCode = DB_UNITNOTFOUND;
		m_csError.Format("Acoustic Unit 1 \"%s\" not found",lpszAUnitName);
		return -1;
	}
	return i;
}




CString CMyDatabase::GetLastError(int *nErrorCode)
{
	if(nErrorCode) *nErrorCode = m_nErrorCode;
	switch(m_nErrorCode)
	{
		case DB_CANNOTOPENDBFILE	:	return m_csError;
		case DB_NULLPOINTER			:	return "Null pointer";
		case DB_DBNOTOPENED			:	return "Database is not opened yet";
		case DB_UNITNOTFOUND		:	return m_csError;
		case DB_INDEXOVERFLOW		:	return "Index overflow";
		case DB_BUFFEROVERFLOW		:	return "Buffer overflow";
		case DB_UNITEXISTED			:	return m_csError;
		case DB_CANNOTCLEANUP		:	return "Can not clean up! Be sure that it isn't being used";
		case DB_CANNOTRELOAD		:	return "Can not reload! Be sure that it isn't being used";
	}
	return "No Error";
}

// get length of an acoustic unit in database; thaodv 180111
DWORD CMyDatabase::GetElementLen(WORD wIndex)
{
	if(wIndex == *(WORD *)(m_cHeader) - 1)
		return m_fAUnits.GetLength() - (*(DWORD *)(m_cHeader + wIndex * 8 + 4 + 2));
	return  (*(DWORD *)(m_cHeader + (wIndex + 1) * 8 + 4 + 2)) - (*(DWORD *)(m_cHeader + wIndex * 8 + 4 + 2));
}

BOOL CMyDatabase::GetAUnitInfo(UNITINFO &info)
{
	if(!this->m_bOpenedDB){
		m_nErrorCode = DB_DBNOTOPENED;
		return FALSE;
	}

	if(!(info.wFlag & DB_DIPINDEX) && !(info.wFlag & DB_DIPNAME))
	{
		m_nErrorCode = DB_UNITNOTFOUND;
		m_csError.Format("Acoustic Unit not found");
		return FALSE;
	}


	if(info.wFlag & DB_DIPINDEX)
	{
		if(info.wIndex > *(WORD *)(m_cHeader) - 1) {
			m_nErrorCode = DB_INDEXOVERFLOW;
			return FALSE;
		}
		memcpy(info.cUnitName,m_cHeader + info.wIndex * 8 + 2,4);
		info.cUnitName[4] = '\0';
	}
	else
	{// bat dau tim kiem o day
		int nIndex; BYTE nCount = 0;
		// tim kiem vi tri cua AUnit trong csdl thaodv 270111
		if(info.wFlag & DB_DIPDELETED)
			nIndex = FindAll(info.cUnitName);
		else
			nIndex = Find(info.cUnitName);
		if(nIndex == -1) return FALSE;
		else nCount ++;
		for(;;)
		{
			
			if(nCount == info.bSameUnitIndex) break;
			else 
			{
				nIndex = FindNext(info.cUnitName,nIndex);
				if (nIndex == -1) return FALSE;
				else nCount++;
			}
		}
		info.wIndex = (WORD)nIndex;
	}

	DWORD dwElementLen = GetElementLen(info.wIndex);

	char *m_cTemp = new char [dwElementLen];
	m_fAUnits.Seek(*(DWORD *)(m_cHeader + 8 * info.wIndex + 4 + 2),CFile::begin);
	m_fAUnits.Read(m_cTemp,dwElementLen);

	if(info.wFlag & DB_DIPDELETED)
	{
		//info.bDeleted = m_cTemp[0];
		info.bDeleted = this->m_stSupInfo[info.wIndex].bDeleted;
	}

	if(info.wFlag & DB_DIPTRANPOINT)
	{
		//info.nTranPoint = *(WORD *)(m_cTemp+1);
		info.nTranPoint = this->m_stSupInfo[info.wIndex].wTranPoint;
	}

	if((info.wFlag & DB_DIPLEN)||(info.wFlag & DB_DIPBUFFER))
	{
		//info.dwDipLen = *(DWORD *)(m_cTemp + 3) - 8;
		info.dwDipLen = this->m_stSupInfo[info.wIndex].dwDipLen;
	}
	if(info.wFlag & DB_CONTEXT)
	{
		// Bo xung ngay 06 thang 12 nam 2005, lay cac thong tin ve context cua Unit
		info.UnitType	= this->m_stSupInfo[info.wIndex].UnitType;
		info.bTone		= this->m_stSupInfo[info.wIndex].bTone;
		info.bLeftTone	= this->m_stSupInfo[info.wIndex].bLeftTone;
		info.bRightTone	= this->m_stSupInfo[info.wIndex].bRightTone;
		info.dwLowFEnergy	= this->m_stSupInfo[info.wIndex].dwLowFEnergy;
		info.dwHighFEnergy	= this->m_stSupInfo[info.wIndex].dwHighFEnergy;
		memcpy(info.cLeftUnitName, m_stSupInfo[info.wIndex].cLeftUnitName,5);
		memcpy(info.cRightUnitName, m_stSupInfo[info.wIndex].cRightUnitName,5);
		// Ket thuc bo xung
	}

	if(info.wFlag & DB_DIPBUFFER)
	{
		info.lpBuffer = new char [info.dwDipLen];
		//memcpy(info.lpBuffer,m_cTemp + 8,info.dwDipLen);
		memcpy(info.lpBuffer,m_cTemp + 28,info.dwDipLen);
	}

	if((info.wFlag & DB_DIPNUMBERMARKS)||(info.wFlag & DB_DIPMARKS))
	{

		info.nNumberPitchMarks = (dwElementLen - 96 - 20 - (*(DWORD *)(m_cTemp + 3)))/(sizeof(DWORD)); 
	}// so diem Pitch

	if(info.wFlag & DB_DIPMARKS)
	{
		info.lpPitchMarks = new DWORD [info.nNumberPitchMarks];

		memcpy(info.lpPitchMarks,m_cTemp +20+ (*(DWORD *)(m_cTemp + 3)),info.nNumberPitchMarks * sizeof(DWORD));
	}

	delete[] m_cTemp;
	return TRUE;	
}

BOOL CMyDatabase::ReadSupInfo()
{
	if(!this->m_bOpenedDB){
		m_nErrorCode = DB_DBNOTOPENED;
		return FALSE;
	}
	for(int i = 0;i<*(WORD*)(m_cHeader);i++)
	{
		m_fAUnits.Seek(*(DWORD *)(m_cHeader + 8 * i + 4 + 2),CFile::begin);
		char cTemp[28];//8];
		m_fAUnits.Read(cTemp,27);//7);
		m_stSupInfo[i].bDeleted = cTemp[0];
		m_stSupInfo[i].wTranPoint = *(WORD *)(cTemp + 1);
		m_stSupInfo[i].dwDipLen = *(DWORD *)(cTemp + 3)-8;

		// Bo xung ngay 06 thang 12 nam 2005, lay cac thong tin ve context cua Unit
		m_stSupInfo[i].UnitType = *(BYTE *)(cTemp + 7);
		m_stSupInfo[i].bTone	= *(BYTE *)(cTemp + 8);
		m_stSupInfo[i].bLeftTone	= *(BYTE *)(cTemp + 9);
		m_stSupInfo[i].bRightTone	= *(BYTE *)(cTemp + 10);
		m_stSupInfo[i].dwLowFEnergy	= *(DWORD *)(cTemp + 11);
		m_stSupInfo[i].dwHighFEnergy= *(DWORD *)(cTemp + 15);
		memcpy(m_stSupInfo[i].cLeftUnitName,cTemp +19,4);
		m_stSupInfo[i].cLeftUnitName[4] = '\0';
		memcpy(m_stSupInfo[i].cRightUnitName,cTemp +23,4);
		m_stSupInfo[i].cRightUnitName[4] = '\0';

		// Ket thuc bo xung
	}
	return TRUE;
}

int CMyDatabase::Find(LPCTSTR lpszAUnitName) // tham so truyen vao la ten cua don vi am can tim; thaodv 180111
{
	if(!this->m_bOpenedDB){
		m_nErrorCode = DB_DBNOTOPENED;
		return -1;
	}

	if(!lpszAUnitName){ 
		m_nErrorCode = DB_NULLPOINTER;
		return -1;
	}

	ASSERT(strlen(lpszAUnitName) < 5);

	char *lpszDBAUnitName = new char [5]; //Allocate storage space for array ; thaodv 180111
	lpszDBAUnitName[4] = '\0';
	BOOL	bFound = FALSE;
	int i;
	for(i = 0; i < *(WORD *)(m_cHeader);i++)
	{
		*(DWORD *)(lpszDBAUnitName) = *(DWORD *)(m_cHeader + i * 8 + 2);
		// lay thong tin trong m_cHeader, luu vao lpszDBAUnitName; thaodv 180111
		//lpszDBAUnitName la ten don vi am trong CSDL thaodv 19052011
		if((!m_stSupInfo[i].bDeleted)&&(strcmp(lpszAUnitName,lpszDBAUnitName)==0)){
		//(!m_stSupInfo[i].bDeleted) la dong lenh khac biet so voi method findAll(); thaodv 180111
		// so sanh tham so dau vao voi lpszDBAUnitName; neu = thi tra ve gia tri TRUE va thoat khoi ham ; thaodv 180111
			bFound = TRUE;
			break;
		}
	}
	delete[] lpszDBAUnitName; //Deallocate storage space ; thaodv 180111
	if(!bFound){
		m_nErrorCode = DB_UNITNOTFOUND;
		m_csError.Format("Acoustic Unit 2 \"%s\" not found",lpszAUnitName);
		CPsola::OutputLastError(m_csError);
		return -1;
	}
	return i;
}

int CMyDatabase::FindNext(LPCTSTR lpszAUnitName, int nIndex)
{
	if(!this->m_bOpenedDB){
		m_nErrorCode = DB_DBNOTOPENED;
		return -1;
	}

	if(!lpszAUnitName){ 
		m_nErrorCode = DB_NULLPOINTER;
		return -1;
	}

	ASSERT(strlen(lpszAUnitName) < 5);

	char *lpszDBAUnitName = new char [5];
	lpszDBAUnitName[4] = '\0';
	BOOL	bFound = FALSE;
	int i;
	for(i = nIndex +1; i < *(WORD *)(m_cHeader);i++)
	{
		*(DWORD *)(lpszDBAUnitName) = *(DWORD *)(m_cHeader + i * 8 + 2);
		if((!m_stSupInfo[i].bDeleted)&&(strcmp(lpszAUnitName,lpszDBAUnitName)==0)){
			bFound = TRUE;
			break;
		}
	}
	delete[] lpszDBAUnitName;
	if(!bFound){
		m_nErrorCode = DB_UNITNOTFOUND;
		//m_csError.Format("Acoustic Unit next \"%s\" not found",lpszAUnitName);
		//CPsola::OutputLastError(m_csError);
		return -1;
	}
	return i;

}
/*
BTypeOfPos: nhan gia tri tu 1-5; y nghia la j? thaodv 200111
bPosInSyl: vi tri trong am tiet
dau ra la &Unit; gia tri dc gan cho &Unit la cac thuoc tinh cua CurrentSyl, LeftSyl, RightSyl
va theo gia tri cua BTypeOfPos
*/
void CMyDatabase::GetUnitContext(SYLLABLESTRUCT CurrentSyl, SYLLABLESTRUCT LeftSyl, SYLLABLESTRUCT RightSyl, 
								 UNITINFO &Unit, BYTE BTypeOfPos, BYTE bPosInSyl)
{
	switch (BTypeOfPos)
	{
		case 1: 
				memcpy(Unit.cLeftUnitName,"SIL",3);	// copy "SIL" kich thuoc 3 bytes vao Unit.cleftUnitName
				Unit.cLeftUnitName[3] = '\0';
				if(CurrentSyl.nAUnit > 1)
				{
					memcpy(Unit.cRightUnitName,CurrentSyl.cSecondAUnit,5);
					Unit.bRightTone	= CurrentSyl.nTon;
				}
				else 
				{
					memcpy(Unit.cRightUnitName,RightSyl.cFirstAUnit,5);
					Unit.bRightTone	= RightSyl.nTon;
				}
				Unit.bTone		= CurrentSyl.nTon;
				Unit.bLeftTone	= 0;
				break;

		case 2:	
				if((CurrentSyl.nAUnit ==3)||((CurrentSyl.nAUnit ==4)&&(bPosInSyl = 2)))
				{
					memcpy(Unit.cLeftUnitName,CurrentSyl.cFirstAUnit,5);
					memcpy(Unit.cRightUnitName,CurrentSyl.cSecondAUnit,5);
				}
				if((CurrentSyl.nAUnit ==4)&&(bPosInSyl = 3))
				{
					memcpy(Unit.cLeftUnitName,CurrentSyl.cSecondAUnit,5);
					memcpy(Unit.cRightUnitName,CurrentSyl.cThirdAUnit,5);
				}

				Unit.bTone		= CurrentSyl.nTon;
				Unit.bLeftTone	= CurrentSyl.nTon;
				Unit.bRightTone	= CurrentSyl.nTon;
				break;

		case 3:
				if(CurrentSyl.nAUnit ==2)
					memcpy(Unit.cLeftUnitName,CurrentSyl.cFirstAUnit,5);	
				if(CurrentSyl.nAUnit ==3)
					memcpy(Unit.cLeftUnitName,CurrentSyl.cSecondAUnit,5);
				if(CurrentSyl.nAUnit ==4)
					memcpy(Unit.cLeftUnitName,CurrentSyl.cThirdAUnit,5);
				
				memcpy(Unit.cRightUnitName,RightSyl.cFirstAUnit,5);
				
				Unit.bTone		= CurrentSyl.nTon;
				Unit.bLeftTone	= CurrentSyl.nTon;
				Unit.bRightTone	= RightSyl.nTon;
				break;
		case 4:
				switch (LeftSyl.nAUnit)
				{
				case 1:
					memcpy(Unit.cLeftUnitName,LeftSyl.cFirstAUnit,5);
					break;
				case 2:
					memcpy(Unit.cLeftUnitName,LeftSyl.cSecondAUnit,5);
					break;
				case 3:
					memcpy(Unit.cLeftUnitName,LeftSyl.cThirdAUnit,5);
					break;
				case 4:
					memcpy(Unit.cLeftUnitName,LeftSyl.cFourthAUnit,5);
					break;
				}
				if(CurrentSyl.nAUnit > 1)
				{
					memcpy(Unit.cRightUnitName,CurrentSyl.cSecondAUnit,5);
					Unit.bRightTone	= CurrentSyl.nTon;
				}
				else 
				{
					memcpy(Unit.cRightUnitName,RightSyl.cFirstAUnit,5);
					Unit.bRightTone	= RightSyl.nTon;
				}
				
				Unit.bTone		= CurrentSyl.nTon;
				Unit.bLeftTone	= LeftSyl.nTon;
				break;
		case 5:
				memcpy(Unit.cRightUnitName,"SIL",3);	
				Unit.cRightUnitName[3] = '\0';
				switch (CurrentSyl.nAUnit)
				{
				case 1: 
					switch (LeftSyl.nAUnit)
					{
					case 1:
						memcpy(Unit.cLeftUnitName,LeftSyl.cFirstAUnit,5);
						break;
					case 2:
						memcpy(Unit.cLeftUnitName,LeftSyl.cSecondAUnit,5);
						break;
					case 3:
						memcpy(Unit.cLeftUnitName,LeftSyl.cThirdAUnit,5);
						break;
					case 4:
						memcpy(Unit.cLeftUnitName,LeftSyl.cFourthAUnit,5);
						break;
					}
					break;
				case 2:
					memcpy(Unit.cLeftUnitName,CurrentSyl.cFirstAUnit,5);
					break;
				case 3:
					memcpy(Unit.cLeftUnitName,CurrentSyl.cSecondAUnit,5);
					break;
				case 4:
					memcpy(Unit.cLeftUnitName,CurrentSyl.cThirdAUnit,5);
					break;
				}
				if(CurrentSyl.nAUnit ==1) Unit.bLeftTone	= LeftSyl.nTon;
				else Unit.bLeftTone = CurrentSyl.nTon;
				Unit.bTone		= CurrentSyl.nTon;
				Unit.bRightTone	= 0;
	}

}

BOOL CMyDatabase::BestUnitSelection(UNITINFO &UnitContext)
{
	//// UNITINFO = Structure of a Unit used to get/put the information of one Unit from/to the Database file; thaodv 180111
	if(!this->m_bOpenedDB){
		m_nErrorCode = DB_DBNOTOPENED;
		return FALSE;
	}
	int nIndex;
	nIndex = Find(UnitContext.cUnitName);
	// tim kiem trong csdl don vi am co ten = cUnitName; tra ve vi tri thaodv 260111
	if(nIndex == -1) return FALSE;
	UNITINFO Info;
	float fToneDistance;

	Info.wIndex = nIndex;
	Info.wFlag = DB_DIPINDEX|DB_CONTEXT;
	if(!GetAUnitInfo(Info)) return FALSE;
	
	float fNote =0;

	
	Num_Best_Unit_Array.Add(0);
	if(!strcmp(UnitContext.cLeftUnitName,"SIL")) 
	{
		PreUnit.wFlag = PreUnit.wFlag & 0x1FF;

	}
	if(!strcmp(UnitContext.cLeftUnitName,Info.cLeftUnitName)) fNote =2;
	if(!strcmp(UnitContext.cRightUnitName,Info.cRightUnitName)) fNote = fNote + 2;
	if(UnitContext.bTone == Info.bTone) fNote = fNote + 2;
	else
	{
		fToneDistance = ToneDistance(UnitContext.bTone,Info.bTone);
		if((Info.bTone==6)||(Info.bTone==3)) fToneDistance = fToneDistance/3; 
		fNote = fNote + 2*fToneDistance;
	}
	if(UnitContext.bLeftTone == Info.bLeftTone)  fNote = fNote + 1;
	else
	{
		fToneDistance = ToneDistance(UnitContext.bLeftTone,Info.bLeftTone);
		fNote = fNote + fToneDistance;
	}
	if(UnitContext.bRightTone == Info.bRightTone)  fNote = fNote + 1;
	else
	{
		fToneDistance = ToneDistance(UnitContext.bRightTone,Info.bRightTone);
		fNote = fNote + fToneDistance;
	}
	
	BYTE bSameUnitIndex;
	UnitContext.bSameUnitIndex = 1;
	UnitContext.wIndex = nIndex;
	
	///////////////////////////////////////////
	// Bo xung ngay 15 thang 02 nam 2005	 //
	// Noi dung: Lay danh sach cac Unit co context thoa man yeu cau
	//										 //
	///////////////////////////////////////////
	int nLastUnit, nUnitOrder;

	nLastUnit = Num_Best_Unit_Array.GetSize() - 1;
	nUnitOrder = Num_Best_Unit_Array.GetAt(nLastUnit);
	Num_Best_Unit_Array.SetAt(nLastUnit,nUnitOrder +1);
	
	DIPDISINFO Dip_Candidate;

	Dip_Candidate.wIndex = UnitContext.wIndex;
	Dip_Candidate.bSameUnitIndex = UnitContext.bSameUnitIndex;
	memcpy(Dip_Candidate.cUnitName, UnitContext.cUnitName,5);
	//
	Dip_Candidate.fTargetCost = fNote;
	//
	DIP_Best_Unit_Array.Add(Dip_Candidate);
	
	//WriteToTextFile(Dip_Candidate.cUnitName);//thaodv 240211
	//cout <<"DIP_Best_Unit_Array.GetAt(1): "<<DIP_Best_Unit_Array.GetAt(1)<< endl; //thaodv 240211
	///////////////////////////////////////////
//	fNoteMax = fNote;
	bSameUnitIndex = UnitContext.bSameUnitIndex;
	int nIndexNext;
	nIndexNext = nIndex;
	for(;;)
	{
		nIndexNext = FindNext(UnitContext.cUnitName,nIndexNext);
		if(nIndexNext == -1) 
		{
			break;
		}
		else 
		{
			bSameUnitIndex ++;
			Info.wIndex = nIndexNext;
			Info.wFlag = DB_DIPINDEX|DB_CONTEXT;
			if(!GetAUnitInfo(Info)) return FALSE;

			fNote =0;
			if(!strcmp(UnitContext.cLeftUnitName,Info.cLeftUnitName)) fNote =2;
			if(!strcmp(UnitContext.cRightUnitName,Info.cRightUnitName)) fNote = fNote + 2;
			if(UnitContext.bTone == Info.bTone) fNote = fNote + 2;
			else
			{
				fToneDistance = ToneDistance(UnitContext.bTone,Info.bTone);
				if((Info.bTone==6)||(Info.bTone==3)) fToneDistance = fToneDistance/3; 
				fNote = fNote + 2*fToneDistance;
			}
			
			if(UnitContext.bLeftTone == Info.bLeftTone)  fNote = fNote + 1;
			else
			{
				fToneDistance = ToneDistance(UnitContext.bLeftTone,Info.bLeftTone);
				fNote = fNote + fToneDistance;
			}
			if(UnitContext.bRightTone == Info.bRightTone)  fNote = fNote + 1;
			else
			{
				fToneDistance = ToneDistance(UnitContext.bRightTone,Info.bRightTone);
				fNote = fNote + fToneDistance;
			}


			///////////////////////////////////////////
			// Bo xung ngay 15 thang 02 nam 2005	 //
			// Noi dung: Lay danh sach cac Unit co context thoa man yeu cau
			//										 //
			///////////////////////////////////////////
			//	int nLastUnit, nUnitOrder;
			nLastUnit = Num_Best_Unit_Array.GetSize() - 1;
			nUnitOrder = Num_Best_Unit_Array.GetAt(nLastUnit);
			Num_Best_Unit_Array.SetAt(nLastUnit,nUnitOrder +1);
			
			Dip_Candidate.wIndex = Info.wIndex;
			Dip_Candidate.bSameUnitIndex = bSameUnitIndex;
			memcpy(Dip_Candidate.cUnitName, Info.cUnitName,5);
			//
			Dip_Candidate.fTargetCost = fNote;
			//
			DIP_Best_Unit_Array.Add(Dip_Candidate);
		}
	}

	PreUnit.wFlag = DB_LEFTCONTEXT;
	PreUnit.wIndex = UnitContext.wIndex; // Bo xung ngay 10 thang 02: luu giu ket qua am duoc chon
	memcpy(PreUnit.cUnitName, UnitContext.cUnitName,5); // Bo xung ngay 10 thang 02: luu giu ket qua am duoc chon
	////////////////////////////////////
	/*FILE *fileopen;
	if( (fileopen = fopen( "outText.txt", "a+t" )) == NULL )
	AfxMessageBox( "The file 'crt_fopen.c' was not opened\n" );
	else
	{
		fwrite(UnitContext.cUnitName,5,1,fileopen);
		char cIndex[5];
		itoa(UnitContext.bSameUnitIndex,cIndex,10);
		fwrite(cIndex,strlen(cIndex),1,fileopen);
		fwrite("\n",strlen("\n"),1,fileopen);
	}
	fclose(fileopen);*/

	return TRUE;

}

////////////////////////////////////////////////////////////////////////////////////////
// This function will connect 2 database files.
////////////////////////////////////////////////////////////////////////////////////////



BOOL CMyDatabase::SpectralDistance(UNITINFO Unit1, UNITINFO Unit2, float &fDistance)
{
	// &fDistance la khoang cach pho; truyen vao dang tham bien
	// ko can return nhung gia tri cua fDistance van thay doi theo
	// tinh toan ben trong ham ; thaodv 180111
	
	 float* mfccEnd1;
     float* mfccBegin2;
     mfccEnd1 = (float*)malloc(12*sizeof(float));
	 mfccBegin2 = (float*)malloc(12*sizeof(float));
	 // Lay ra cac he so MFCC 
     GetMFCCEnd(Unit1.wIndex, mfccEnd1);
	 GetMFCCBegin(Unit2.wIndex, mfccBegin2);  
	 // Tinh toan khoang cach pho
     fDistance = MFCCdistance(mfccEnd1,mfccBegin2);     
     fDistance = 10 - 5*(fDistance);     
     free(mfccEnd1);
	 free(mfccBegin2);
     
     return TRUE; 

}
///////////////////////////////////////////////////////////////////////////////////////

void CMyDatabase::ListSelUnit()
{
	int i, nCounter = 0;
	//FILE *fileopen;

	//if( (fileopen = fopen( "SelectedCandidat.path.txt", "a+t" )) == NULL )
	//{
	//	AfxMessageBox( "The file 'SelectedCandidat.path.txt' was not opened\n" );
	//	return;
	//}
	DistanceMatrix();
	ComputeShortestPathArray();
	
	for(i=0; i<Num_Best_Unit_Array.GetSize();i++)
	{
		int nSize;
		nSize = Num_Best_Unit_Array.GetAt(i);
		for(int j=0; j<nSize; j++)
		{
			DIPDISINFO OutUnit;
			OutUnit = DIP_Best_Unit_Array.GetAt(nCounter++);

			/*char cbuff[20];
			sprintf(cbuff,"%5s %3d %3d ", OutUnit.cUnitName, OutUnit.bSameUnitIndex,OutUnit.wIndex);
			fwrite(cbuff,strlen(cbuff),1,fileopen);

			sprintf(cbuff," Shortest Path:");
			fwrite(cbuff,strlen(cbuff),1,fileopen);

			for(int k=0;k<OutUnit.wPathSize;k++)
			{
				sprintf(cbuff,"%3d ",OutUnit.wCurrentPath[k] );
				fwrite(cbuff,strlen(cbuff),1,fileopen);

			}

			sprintf(cbuff," Path score: %0.2f \n",OutUnit.fShortestPath);
			fwrite(cbuff,strlen(cbuff),1,fileopen);*/
			//////////
		}
		//fwrite("\n",strlen("\n"),1,fileopen);
	}

	/*char cbuff[20];
	//sprintf(cbuff," Shortest Path:");
	//fwrite(cbuff,strlen(cbuff),1,fileopen);
	for(int k=0;k<Best_Units_Path.wPathSize;k++)
		{
			sprintf(cbuff,"%3d ",Best_Units_Path.wCurrentPath[k] );
			fwrite(cbuff,strlen(cbuff),1,fileopen);
		}
	sprintf(cbuff," Path score: %0.2f \n",Best_Units_Path.fShortestPath);
	fwrite(cbuff,strlen(cbuff),1,fileopen);

	sprintf(cbuff,"DIP_Arr %d Cont %d \n",DIP_Best_Unit_Array.GetSize(),nCounter);
	fwrite(cbuff,strlen(cbuff),1,fileopen);

	fclose(fileopen);*/
	return;

}

//////////////////////////////////////////////////////////////////////////////////
// This function calculates the distance of context of two acoustic units which were 
// selected for synthesizing
///////////////////////////////////////////////////////////////////////////////////
float CMyDatabase::ContextDistance(DIPDISINFO Unit1, DIPDISINFO Unit2)
{
	UNITINFO Info1, Info2;

	if((!strcmp(Unit1.cUnitName,"SIL"))&&(!Unit1.wIndex))
	{
		strcpy(Info1.cUnitName,Unit1.cUnitName);
		strcpy(Info1.cLeftUnitName,"SIL");
		strcpy(Info2.cRightUnitName, "SIL"); //02/06/2006
		Info1.bRightTone = 0;
		Info1.bTone = 0;
		Info1.bLeftTone =0;
	}

	else
	{
		Info1.wIndex = Unit1.wIndex;
		Info1.wFlag = DB_DIPINDEX|DB_CONTEXT;
		GetAUnitInfo(Info1);
	}

	
	/////////////////////////////////////////////////////////////////////////////////////////////////
	// Adding 02/06/2006
	// Adding the context distance of the last Unit in the phrase
	/////////////////////////////////////////////////////////////////////////////////////////////////
	
	if((!strcmp(Unit2.cUnitName,"SIL"))&&(!Unit2.wIndex))
	{
		strcpy(Info2.cUnitName,Unit2.cUnitName);
		strcpy(Info2.cLeftUnitName,"SIL");
		strcpy(Info2.cRightUnitName, "SIL");
		Info2.bRightTone = 0;
		Info2.bTone = 0;
		Info2.bLeftTone =0;
	}
	// End of Adding
	else
	{
		Info2.wIndex = Unit2.wIndex;
		Info2.wFlag = DB_DIPINDEX|DB_CONTEXT;
		GetAUnitInfo(Info2);
	}
	float fNote =0;
	float fToneDistance =0;
	

	if(!strcmp(Info1.cRightUnitName,Info2.cUnitName)) fNote = 2;
	if(!strcmp(Info1.cUnitName,Info2.cLeftUnitName)) fNote = fNote + 2;
	if(Info1.bRightTone == Info2.bTone) fNote = fNote + 2;
	else
	{
		fToneDistance = ToneDistance(Info1.bRightTone ,Info2.bTone);
		fNote = fNote + 2*fToneDistance;
	}
	if(Info1.bTone == Info2.bLeftTone)  fNote = fNote + 2;
	else
	{
		fToneDistance = ToneDistance(Info1.bTone ,Info2.bLeftTone);
		fNote = fNote + 2*fToneDistance;
	}

	return fNote;
}
//////////////////////////////////////////////////////////////////////////////////
// This function calculates the context distances of all member of two adjacent 
// unit layers which were selected for synthesizing
///////////////////////////////////////////////////////////////////////////////////

BOOL CMyDatabase::DistanceMatrix()
{
	int i,q, nCounter = 0;
	//nCounter la bien dem; thaodv 200111
	
	int nPositionLayer1, nPositionLayer2;
	DIPDISINFO UnitLayer2;
	for(i=0; i<Num_Best_Unit_Array.GetSize();i++)
	{
		q = Num_Best_Unit_Array.GetSize();
		int nSize;
		nSize = Num_Best_Unit_Array.GetAt(i);
		nPositionLayer1 = nCounter;
		for(int j=0; j<nSize; j++)
		{
			DIPDISINFO UnitLayer1;
			UnitLayer1 = DIP_Best_Unit_Array.GetAt(nCounter);
			
			if(i==0)
			{

				strcpy(UnitLayer2.cUnitName,"SIL");
				UnitLayer2.wIndex =0;

				DIP_Best_Unit_Array.ElementAt(nCounter).fDistArray[0] = 
										ContextDistance(UnitLayer2,UnitLayer1)/2 + 
										DIP_Best_Unit_Array.ElementAt(nCounter).fTargetCost/2;

			}
			else
			{
				int nSizeOfPre;
				nSizeOfPre = Num_Best_Unit_Array.GetAt(i-1);
				nPositionLayer2 = nPositionLayer1 - nSizeOfPre;
				for(int k=0; k<nSizeOfPre;k++)
				{
					//DIPDISINFO UnitLayer2;
					UnitLayer2 = DIP_Best_Unit_Array.GetAt(nPositionLayer2 + k);
					//UnitLayer1.fDistArray[j] = ContextDistance(UnitLayer1,UnitLayer2);
					UNITINFO temp1, temp2;
					memcpy(temp1.cUnitName,UnitLayer1.cUnitName,5);
					temp1.wIndex = UnitLayer1.wIndex;
					temp1.bSameUnitIndex = UnitLayer1.bSameUnitIndex;

					memcpy(temp2.cUnitName,UnitLayer2.cUnitName,5);
					temp2.wIndex = UnitLayer2.wIndex;
					temp2.bSameUnitIndex = UnitLayer2.bSameUnitIndex;

					float fSpectralDis;

					if(!SpectralDistance(temp2,temp1,fSpectralDis)) return FALSE;
					// tinh toan khoang cach pho giua temp1 va temp2. gia tri tra ve luu vao trong fSpectralDis; thaodv 180111
					

					DIP_Best_Unit_Array.ElementAt(nCounter).fDistArray[k] = ContextDistance(UnitLayer2,UnitLayer1)/2
																			+ 2.0*fSpectralDis + DIP_Best_Unit_Array.ElementAt(nCounter).fTargetCost/2;//(6 - 3*fSpectralDis);
					/////////////////////////////////////////////////////////////////////////////////////////////////
					// Adding 02/06/2006
					// Adding the context distance of the last Unit in the phrase
					/////////////////////////////////////////////////////////////////////////////////////////////////
					if(i== (Num_Best_Unit_Array.GetSize()-1))
					{
						strcpy(UnitLayer2.cUnitName,"SIL");
						UnitLayer2.wIndex =0;
						DIP_Best_Unit_Array.ElementAt(nCounter).fDistArray[k] += ContextDistance(UnitLayer1,UnitLayer2)/2;
					}

					// End of Adding
				}
			}
			nCounter++;
		}
	}
	return TRUE;
}

void CMyDatabase::ComputeShortestPathArray()
{
	int i, nColSize, nRowSize;
	float min = 0;
	float fMax =0;
	int nPositionLayer1, nPositionLayer2;
	WORD wMaxPos=0;

	nRowSize = Num_Best_Unit_Array.GetSize();
	int nCounter = 0;

	for(i = 0; i< nRowSize; i++)
	{
		nColSize = Num_Best_Unit_Array.GetAt(i);
		nPositionLayer1 = nCounter;
		float fShortestPath = 0;
		for(int j=0; j<nColSize; j++)
		{
			int nSizeOfPre;

			
			if(i==0)
			{
				DIP_Best_Unit_Array.ElementAt(nCounter).fShortestPath = DIP_Best_Unit_Array.ElementAt(nCounter).fDistArray[0];
				DIP_Best_Unit_Array.ElementAt(nCounter).wCurrentPath = new WORD[i+1];
				DIP_Best_Unit_Array.ElementAt(nCounter).wPathSize = i+1;//nRowSize;
				DIP_Best_Unit_Array.ElementAt(nCounter).wCurrentPath[i] = nCounter;
			}
			else
			{
				nSizeOfPre = Num_Best_Unit_Array.GetAt(i-1);
				nPositionLayer2 = nPositionLayer1 - nSizeOfPre;	
				fMax = 0; wMaxPos=0;
				
				DIP_Best_Unit_Array.ElementAt(nCounter).wCurrentPath = new WORD[i+1];
				DIP_Best_Unit_Array.ElementAt(nCounter).wPathSize = i+1;//nRowSize;
				for(int k=0; k<nSizeOfPre; k++)
				{
					fShortestPath = DIP_Best_Unit_Array.ElementAt(nCounter).fDistArray[k] +
										DIP_Best_Unit_Array.ElementAt(nPositionLayer2 + k).fShortestPath;
					if (fShortestPath > fMax)
					{
						fMax = fShortestPath;
						wMaxPos = k;
					}
				}
				DIP_Best_Unit_Array.ElementAt(nCounter).fShortestPath = fMax;
				memcpy(DIP_Best_Unit_Array.ElementAt(nCounter).wCurrentPath,DIP_Best_Unit_Array.ElementAt(nPositionLayer2 + wMaxPos).wCurrentPath, (i-1)*sizeof(WORD));
				
			
				DIP_Best_Unit_Array.ElementAt(nCounter).wCurrentPath[i-1] = DIP_Best_Unit_Array.ElementAt(nPositionLayer2 + wMaxPos).bSameUnitIndex;//nPositionLayer2 + wMaxPos;
				DIP_Best_Unit_Array.ElementAt(nCounter).wCurrentPath[i] = DIP_Best_Unit_Array.ElementAt(nCounter).bSameUnitIndex;//nCounter - nPositionLayer1 +1;
			}

			nCounter++;
		}
	}
	
	nColSize = Num_Best_Unit_Array.GetAt(nRowSize-1);

	nPositionLayer1 = DIP_Best_Unit_Array.GetSize() - nColSize;
	fMax = 0;
	for(i=0; i<nColSize; i++)
		{
			if(DIP_Best_Unit_Array.ElementAt(nPositionLayer1+i).fShortestPath > fMax)
			{
				fMax = DIP_Best_Unit_Array.ElementAt(nPositionLayer1+i).fShortestPath;
				wMaxPos = nPositionLayer1+i;
			}
		}
	Best_Units_Path.fShortestPath = fMax;
	Best_Units_Path.wCurrentPath = new WORD[nRowSize];
	memcpy(Best_Units_Path.wCurrentPath,DIP_Best_Unit_Array.ElementAt(wMaxPos).wCurrentPath, nRowSize*sizeof(WORD));
	// copy duong di ngan nhat tu DIP_Best_Unit_Array vao Best_Units_Path; thaodv 200111
	Best_Units_Path.wPathSize = nRowSize;


}

DIPDISINFO CMyDatabase::GetBestUnit(WORD index)
{
	DIPDISINFO BestUnit;
	BestUnit = DIP_Best_Unit_Array.GetAt(index);
	return BestUnit;

}

BYTE CMyDatabase::GetPosBestUnit(WORD index)
{

	if(index>= Best_Units_Path.wPathSize) return 0;

	return Best_Units_Path.wCurrentPath[index];

}



void CMyDatabase::EmptyBestUnitArray()
{
	DIP_Best_Unit_Array.RemoveAll();
	Num_Best_Unit_Array.RemoveAll();
}



float CMyDatabase::ToneDistance(BYTE Tone1, BYTE Tone2)
{
	int ToneVector[8][2] = {0,  0,
							-1, 1,
							1,  4,
							-1, 2,
							1,  1,
							-1, 6,
							2,  1,
							-1, 1};// khong khop 100% voi bang 3-2, trang 47 do an DSP thaodv 180111
	float fDistance;
	if((Tone1==0)||(Tone2==0)) fDistance = 0.5f;
	else
		fDistance = 0.1f*float(abs(ToneVector[Tone1-1][0] - ToneVector[Tone2-1][0]) + ToneVector[Tone1-1][1] + ToneVector[Tone2-1][1]);
	// cong thuc 3.13 trang 47 do an DSP thaodv 210111
	// cac he so trong cong thuc 3.13 deu bang 0.1f thaodv
	
	return (1-fDistance);
}
// Cac ham de lay ra cac he so MFCC trong CSDL, ket qua tra ve trong mang result thaodv 270111
void CMyDatabase::GetMFCCBegin(WORD wIndex, float* result)
{
	DWORD address, elementLen;
	int i = 0;		
	// Lay ra dia chi va do dai cua vung du lieu cua don vi am wIndex
	m_fAUnits.Seek(8*wIndex + 4 + 2, CFile::begin);	
	m_fAUnits.Read(&address, 4);
	elementLen = GetElementLen(wIndex);
	// Lay ra 12 he so MFCC begin, ket qua tra ve trong mang result
	for(i = 0;i<12;i++)
	{			
		m_fAUnits.Seek(address + elementLen - 96 + i*4, CFile::begin);
		m_fAUnits.Read(&result[i],4);
	}		
}
// khac biet giua GetMFCCBegin va End la Begin-96; End-48;
void CMyDatabase::GetMFCCEnd(WORD wIndex, float* result)
{
	DWORD address, elementLen;
	int i = 0;	
	// Lay ra dia chi va do dai cua vung du lieu cua don vi am wIndex trong CSDL
	m_fAUnits.Seek(8*wIndex + 4 + 2, CFile::begin);	
	m_fAUnits.Read(&address, 4);	
	elementLen = GetElementLen(wIndex);
	// Lay ra 12 he so MFCC end, ket qua tra ve trong mang result
	for(i = 0;i<12;i++)
	{			
		m_fAUnits.Seek(address + elementLen - 48 + i*4, CFile::begin);		
		m_fAUnits.Read(&result[i],4);
	}	
}
// Ham tinh khoang cach MFCC
float CMyDatabase::MFCCdistance(float* mfcc1, float* mfcc2)
{
     int j,nCounter;
     float sum_sq_x,sum_sq_y,sum_coproduct,sweep,delta_x,delta_y;
     float mean_x,mean_y,pop_sd_x,pop_sd_y,cov_x_y,correlation;
     
     nCounter = 2;
     sum_sq_x = 0;
     sum_sq_y = 0;
     sum_coproduct = 0;
     mean_x = mfcc1[0]; 
     mean_y = mfcc2[0];
     
     for(j=0; j<12; j++)
      {
           if(j==0) continue;
           sweep = (float)(nCounter - 1.0)/nCounter;     
           delta_x = mfcc1[j] - mean_x;
           delta_y = mfcc2[j] - mean_y;
           sum_sq_x += delta_x * delta_x * sweep;
           sum_sq_y += delta_y * delta_y * sweep;
		   sum_coproduct += delta_x * delta_y * sweep;
		   mean_x += delta_x / nCounter;
		   mean_y += delta_y / nCounter;
		   nCounter++;         
      } 
      pop_sd_x = sqrt(sum_sq_x/nCounter);
      pop_sd_y = sqrt(sum_sq_y/nCounter);
      cov_x_y  = sum_coproduct/nCounter;
      correlation = cov_x_y/(pop_sd_x*pop_sd_y);
     
     return (float)(2*(1.0-correlation));     
}
////
void CMyDatabase::WriteToTextFile(CString cstr)
{
	//ofstream txtFile("txt_MyDatabase.txt");
	txtFile.open("txt_MyDatabase.txt",ios::app);
	if (txtFile.is_open())
	  {
		//txtFile << "This is a line.\n";
		//txtFile << "This is another line.\n";
		txtFile <<cstr << "\n";
		txtFile.close();
	  }
	  else cout << "Unable to open file";


		
}
